import { Map, ResizeCanvas, ResizeCanvasHead } from "./map.js"
import { get_device, add_event_listener, remove_event_listener } from "./utils.js";
import { Problem } from "./problem.js";

const step_show_element = document.getElementById( 'steps_show' );
const head_title = document.getElementById( 'head_title_edit' );
const canvas = document.getElementById( 'myCanvas' );
const canvas_head = document.getElementById( 'canvas_head' );
ResizeCanvas( canvas );
ResizeCanvasHead( canvas_head );

const device = get_device( canvas );

const context = canvas.getContext( '2d' )
const map = new Map( canvas.width, canvas.height );

function RenderFrame() {
    context.clearRect( 0, 0, canvas.width, canvas.height );
    map.DrawMap( context );
    map.DrawCars( context );
}

function addRank( rank_list ) {
    let data = [];
    console.log( rank_list );
    rank_list.forEach( ( element, index ) => {
        data.push( {
            'rank': index + 1, 'name': element.name, 'step': element.step
        } );
    } );

    return data;
}

function RenderRankList( rank_list ) {
    const table = layui.table;

    let rank_list_with_rank = addRank( rank_list );
    table.render( {
        elem: '#rank_table', data: rank_list_with_rank, even: true, cols: [
            [
                { field: 'rank', width: 61, title: '排名', fixed: 'left' }, { field: 'name', title: '用户名' },
                { field: 'step', width: 80, title: '步数' }
            ]
        ], text: {
            none: '此关卡暂无人通关'
        }, page : true
    } );
}

export class Game {
    /**
     *
     * @param {Problem} problem
     * @param switchToNextProblem
     * @param onWin
     * @param {Boolean} auto_next
     */
    constructor( problem, switchToNextProblem, onWin, auto_next ) {
        this.problem = problem;
        this.switchToNextProblem = switchToNextProblem;
        this.onWin = onWin;

        this.accessing = {
            index: -1, car: null, car_round_rect: null, diff_from_mouse: { x: 0, y: 0 }
        };

        this.move_list = [];
        this.step = 0;

        this.auto_next = auto_next | false;

        this.up = this.on_touch_up.bind( this );
        this.down = this.on_touch_down.bind( this );
        this.move = this.on_touch_move.bind( this );
    }

    recordMove( new_car ) {
        let car = this.accessing.car;
        this.move_list = this.move_list.slice( 0, this.step );

        this.move_list.push( {
            car_index: this.accessing.index, old: { x: car.x, y: car.y }, new: { x: new_car.x, y: new_car.y }
        } );
    }

    moveNext() {
        let step = this.move_list.length;
        if ( this.step >= step ) {
            alert( "没有下一步了" );
            return;
        }

        let car = this.problem.cars[ this.move_list[ this.step ].car_index ];
        car.ResetTo( this.move_list[ this.step ].new );
        map.ResetCar( this.move_list[ this.step ].car_index, car );
        this.step += 1;
        this.ShowSteps( this.step );
        RenderFrame()
    }

    movePrev() {
        if ( this.step <= 0 ) {
            alert( "没有上一步了" );
            return;
        }

        let car = this.problem.cars[ this.move_list[ this.step - 1 ].car_index ];
        car.ResetTo( this.move_list[ this.step - 1 ].old );
        map.ResetCar( this.move_list[ this.step - 1 ].car_index, car );
        this.step -= 1;
        this.ShowSteps( this.step );
        RenderFrame()
    }

    on_touch_move() {
        if ( this.accessing.index === -1 ) {
            return;
        }

        map.MoveCar( device, this.accessing.diff_from_mouse, this.accessing.index, this.accessing.car.allow_direction );
        RenderFrame()
    }

    on_touch_up() {
        remove_event_listener( canvas, 'up', this.up );
        remove_event_listener( canvas, 'move', this.move );

        let car = this.accessing.car;
        let new_car = map.GetAdaptedCar( this.accessing.index );

        if ( car.x === new_car.x && car.y === new_car.y ) {
            map.ResetCar( this.accessing.index, car );
            RenderFrame();
            return;
        }

        this.recordMove( new_car );
        car.ResetTo( new_car );
        map.ResetCar( this.accessing.index, car );
        RenderFrame();
        this.step += 1;
        this.ShowSteps( this.step );

        if ( !this.problem.IsSolved() ) {
            return;
        }

        this.onWin(this.move_list);

        if ( this.auto_next == true ) {
            this.switchToNextProblem();
            return;
        }

        layer.confirm( '恭喜你通关，是否下一关？', null, ( index ) => {
            layer.close( index );
            this.switchToNextProblem();
        }, function ( index ) {
            layer.close( index );
        } );
    }

    on_touch_down() {
        let car_index = map.get_touch_on_which_car( device );
        if ( car_index === -1 ) {
            this.accessing = {
                index: -1, car: null, car_round_rect: null, diff_from_mouse: { x: 0, y: 0 }
            };
            return;
        }

        this.accessing.index = car_index;
        this.accessing.car = this.problem.cars[ car_index ];
        this.accessing.car_round_rect = map.car_round_rects[ car_index ];
        this.accessing.diff_from_mouse.x = device.x - this.accessing.car_round_rect.x;
        this.accessing.diff_from_mouse.y = device.y - this.accessing.car_round_rect.y;

        add_event_listener( canvas, 'move', this.move );
        add_event_listener( canvas, 'up', this.up );
    }

    clearEnvironment() {
        this.accessing = {
            index: -1, car: null, car_round_rect: null, diff_from_mouse: { x: 0, y: 0 }
        };
        this.step = 0;
        this.move_list = [];
    }

    /**
     *
     * @param {Problem} problem
     */
    SetProblem( problem ) {
        this.problem = problem;
        this.clearEnvironment();
    }

    /**
     * @param {Boolean} auto_next 
     */
    SetAutoNext( auto_next ) {
        this.auto_next = auto_next;
    }

    Launch() {
        this.clearEnvironment();
        map.BuildCarRoundRectangles( this.problem.cars );
        add_event_listener( canvas, 'down', this.down );

        head_title.innerText = this.problem.problem_id;
        RenderFrame();
        RenderRankList( this.problem.rank_list );
        this.ShowSteps( this.step );
    }


    RefreshRankList() {
        this.problem.GetRankList();
        RenderRankList( this.problem.rank_list );
    }


    ResetGame() {
        if ( this.step == 0 ) {
            return;
        }

        if ( confirm( "重置步骤将要从头玩过这一关，确定要重置吗？" ) ) {
            this.problem.ResetCars();
            this.Launch();
        }
    }


    ShowSteps( steps ) {
        step_show_element.innerHTML = "已走步数：" + steps;
    }
}